//
// Created by ttao on 2022/7/26.
//
#include "http_tmalloc.h"
#include "http_alloc.h"

size_t tfree(void * ptr)
{
    if(ptr == NULL) return -1;
    size_t usable = 0;
    tfree_usable(ptr, &usable);
    return usable;
}
static inline void * real_ptr(void *ptr)
{
    return (char*)ptr - PREFIX_SIZE;
}
// usable实际可用的内存大小
void *ttrymalloc_usable(size_t size, size_t * usable)
{
    ASSERT_NO_SIZE_OVERFLOW(size);
    void * ptr = http_malloc(MALLOC_MIN_SIZE(size) + PREFIX_SIZE);
    if(!!ptr)
    {
        *((size_t*)ptr) = size;
        update_tmalloc_stat_alloc(size + PREFIX_SIZE);
        if(usable) *usable = size;
        return ptr + PREFIX_SIZE;
    }
}
// usable实际可用的内存大小
void *ttrycalloc_usable(size_t size, size_t * usable)
{
    ASSERT_NO_SIZE_OVERFLOW(size);
    void * ptr = calloc(1, MALLOC_MIN_SIZE(size) + PREFIX_SIZE);
    if(!ptr) return NULL;
    update_tmalloc_stat_alloc(size + PREFIX_SIZE);
    if(usable) *usable = size;
    return ptr;
}


void *ttryrealloc_usable(void *ptr, size_t size, size_t *usable)
{
    ASSERT_NO_SIZE_OVERFLOW(size);
    void *realptr;
    size_t oldsize;
    void *newptr;
    if(ptr == NULL)
        return ttrymalloc_usable(size, usable);
    if(size <= 0 && ptr != NULL)
    {
        tfree(ptr);
        if(usable) *usable = 0;
        return NULL;
    }
    realptr = real_ptr(ptr);
    oldsize = *((size_t *)realptr);
    newptr = realloc(realptr, size+PREFIX_SIZE);
    if(newptr == NULL)
    {
        if(usable) *usable = 0;
        return NULL;
    }
    update_tmalloc_stat_free(oldsize);
    update_tmalloc_stat_alloc(size + PREFIX_SIZE);
    if(usable) *usable = size;
    return (char *)newptr + PREFIX_SIZE;
}
void *tmalloc_usable(size_t size, size_t * usable)
{
    void *ptr = ttrymalloc_usable(size, usable);
    if(!ptr) tmalloc_oom_handler(size);
    return ptr;
}
void *tmalloc(size_t size)
{
    if(size <= 0)return NULL;
    return tmalloc_usable(size, NULL);
}

void *tcalloc_usable(size_t size, size_t * usable)
{
    void *ptr = ttrycalloc_usable(size, usable);
    if(!ptr) tmalloc_oom_handler(size);
    return ptr;
}

void *trealloc_usable(void *ptr, size_t size, size_t * usable)
{
    ptr = ttryrealloc_usable(ptr, size, usable);
    if(ptr == NULL && size > 0) tmalloc_oom_handler(size);
    return ptr;
}

void *trealloc(void *ptr, size_t size)
{
    ptr = ttryrealloc_usable(ptr, size, NULL);
    if(ptr == NULL && size > 0) tmalloc_oom_handler(size);
    return ptr;
}

void *ttryrealloc(void *ptr, size_t size)
{
    ptr = ttryrealloc_usable(ptr, size, NULL);
    return ptr;
}
size_t tmalloc_size(void *ptr)
{
    void * realptr = real_ptr(ptr);
    size_t size = *((size_t*)realptr);
    return size + PREFIX_SIZE;
}
void tfree_usable(void *ptr, size_t *usable)
{
    if (ptr == NULL) return;
    update_tmalloc_stat_free(*usable = tmalloc_size(ptr));
    http_free(real_ptr(ptr));
}